/**
 * Yaml访问器
 */
import yaml from 'js-yaml';

export default class Yaml {

    #config = {};
    indent = 2;

    constructor(content, indent) {
        if (content) {
            if (typeof content === 'string') {
                this.#config = yaml.load(content) || {};
            } else if (typeof content === 'object') {
                Object.assign(this.#config, content);
            }
        }
        if (indent > 0) {
            this.indent = indent;
        }
    }

    /**
     * 获取值
     * @param {[String]} keys 键清单
     * @return {*} 值
     */
    get(keys = []) {
        if (!Array.isArray(keys)) {
            throw new TypeError('keys必须是数组');
        }
        let value = this.#config;
        for (let k of keys) {
            if (typeof k !== 'string') {
                throw new TypeError('keys中的元素必须是字符串');
            }
            if (typeof value === 'object') {
                value = value[k];
            } else {
                return undefined;
            }
        }
        return value;
    }

    /**
     * 设置值
     * @param {[String]} keys 键清单
     * @param {*} value 值
     */
    set(keys, value) {
        let parent = this.#getParentNode(keys);
        parent[keys[keys.length - 1]] = value;
    }

    #getParentNode(keys) {
        if (!Array.isArray(keys) || keys.length === 0) {
            throw new TypeError('keys必须是非空数组');
        }
        // 确保路径上的所有父对象都存在
        let parent = this.#config;
        for (let i = 0; i < keys.length - 1; i++) {
            const key = keys[i];
            if (typeof key !== 'string') {
                throw new TypeError('keys中的元素必须是字符串');
            }
            if (parent[key] === undefined || parent[key] === null) {
                parent[key] = {};
            }
            parent = parent[key];
        }
        return parent;
    }

    /**
     * 仅当值不存在时设置
     * @param {[String]} keys 键清单
     * @param {*} value 值
     * @returns {boolean} 是否设置成功
     */
    setIfAbsent(keys, value) {
        let parent = this.#getParentNode(keys);
        const lastKey = keys[keys.length - 1];
        if (parent[lastKey] !== undefined && parent[lastKey] !== null) {
            return false;
        }
        parent[lastKey] = value;
        return true;
    }

    remove(keys) {
        if (!Array.isArray(keys) || keys.length === 0) {
            throw new TypeError('keys必须是非空数组');
        }
        
        // 验证所有key必须是字符串
        for (const key of keys) {
            if (typeof key !== 'string') {
                throw new TypeError('keys中的元素必须是字符串');
            }
        }
        
        // 如果只有一个键，直接从根配置中删除
        if (keys.length === 1) {
            if (keys[0] in this.#config) {
                delete this.#config[keys[0]];
                return true;
            }
            return false;
        }
        
        // 递归删除并检查父节点
        const removeRecursive = (obj, keyPath, index) => {
            // 已到达倒数第二层
            if (index === keyPath.length - 1) {
                const lastKey = keyPath[index];
                if (lastKey in obj) {
                    delete obj[lastKey];
                    return true;
                }
                return false;
            }
            
            const currentKey = keyPath[index];
            if (!(currentKey in obj) || typeof obj[currentKey] !== 'object' || Array.isArray(obj[currentKey])) {
                return false; // 路径不存在或不是对象
            }
            
            const result = removeRecursive(obj[currentKey], keyPath, index + 1);
            
            // 如果删除成功且当前节点为空对象，则删除当前节点
            if (result && Object.keys(obj[currentKey]).length === 0) {
                delete obj[currentKey];
            }
            
            return result;
        };
        
        return removeRecursive(this.#config, keys, 0);
    }

    isEmpty() {
        return Object.keys(this.#config).length === 0;
    }

    forEach(consumer) {
        const traverse = (obj, path = []) => {
            if (obj && typeof obj === 'object') {
                if (Array.isArray(obj)) {
                    // 将数组作为叶子节点处理
                    consumer(path, obj);
                } else {
                    for (const [key, value] of Object.entries(obj)) {
                        const currentPath = [...path, key];
                        if (value === null || typeof value !== 'object' || Array.isArray(value)) {
                            // 叶子节点：null、非对象值或数组
                            consumer(currentPath, value);
                        } else {
                            // 继续遍历子节点（普通对象）
                            traverse(value, currentPath);
                        }
                    }
                }
            }
        };
        traverse(this.#config);
    }

    toString() {
        if (this.isEmpty()) {
            return '';
        }
        return yaml.dump(this.#config, {
            indent: this.indent,
            lineWidth: -1,
            quotingType: '"',
            forceQuotes: false,
        });
    }

}
